//-------------------------------------------------------------------
//	Copyright (c) 2010-2012 Zhirnov Andrey
//	This file is part of the "UXGEN" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#include "Window.h"
#include "OS.h"

namespace Engine
{
namespace CoreSystems
{
	
//-------------------------- IWindow ------------------------------//
/*
=================================================
	
=================================================
*/
	IWindow::IWindow(IThread *pThread, TGLWindow *pWnd, CRender *pRender):
		_pThread(pThread), _pWindow(pWnd), _pRender(pRender)
	{
	}
	
/*
=================================================
	
=================================================
*/
	void IWindow::Release()
	{
		THREADMAN()->RemoveThread( _pThread );
		delete this;
	}



//------------------------ CMainWindow ----------------------------//
/*
=================================================
	
=================================================
*/
	CMainWindow::CMainWindow():
		IWindow( &_cThread, &_cWindow, &_cRender ),
		_cWndClass("UXGENWndClass" + CORE()->GetInstanceId())
	{}

/*
=================================================
	
=================================================
*/
	CMainWindow::~CMainWindow()
	{}
	
/*
=================================================
	
=================================================
*/
	bool CMainWindow::Create(const TGLWindow::TDescriptorExt &sDesc, const char *pCaption, const char *pIcon)
	{
		THandles	s_hnd.pClass = &_cWndClass;
		TOsApi::GetInstance( s_hnd );

		CHECK_RETURN( _cIcon.Load( pIcon ) );
		CHECK_RETURN( TOsApi::RegisterClass( s_hnd, e_wc_style::WINDOW, _cIcon.Handle() ) );
		
		CHECK_RETURN( _cWindow.CreateGL( sDesc, pCaption, &_cWndClass ) );
		_cWindow.AddUpdater( &_cThread );
		CHECK_RETURN( _cInput.Init( &_cWindow ) );
		_cWindow.Show();

		THREADMAN()->AddThread( _pThread );
		return true;
	}

/*
=================================================
	
=================================================
*/
	bool CMainWindow::Create(const TGLWindow::TDescriptorExt &sDesc, const char *pCaption, TWindowClass *pClass)
	{
		ASSERT( pClass == nullptr && "this window use own window class" );

		CHECK_RETURN( _cWindow.CreateGL( sDesc, pCaption, &_cWndClass ) );
		_cWindow.AddUpdater( &_cThread );

		CHECK_RETURN( _cInput.Init( &_cWindow ) );
		_cWindow.Show();

		THREADMAN()->AddThread( _pThread );
		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool CMainWindow::CreateShared(e_thread::type eType, IWindow *&pWnd)
	{
		TGLWindow::TDescriptorExt	s_desc;

		s_desc.sDesc	= _cWindow.Descriptor();
		s_desc.sGLDesc	= _cWindow.GLDescriptor();
		s_desc.sGLDesc.hSharedRC	= _cWindow.Handles().hRC;
		s_desc.sDesc.bFullScreen	= false;

		if ( eType == e_thread::LOAD_CONTEXT )
		{
			TAutoPtr< CLoadWindow, CEngBaseObject >		p_wnd = new CLoadWindow( this );
			
			s_desc.sGLDesc.bVSync = false;

			CHECK_RETURN( p_wnd->Create( s_desc, nullptr, &_cWndClass ) );
			_aShared.PushBack( p_wnd.ptr() );
			pWnd = p_wnd.ptr();
			
			p_wnd.Reset();
			return true;
		}

		if ( eType == e_thread::RENDER_WINDOW )
		{
			TAutoPtr< CRenderWindow, CEngBaseObject >	p_wnd = new CRenderWindow( this );

			CHECK_RETURN( p_wnd->Create( s_desc, nullptr, &_cWndClass ) );
			_aShared.PushBack( p_wnd.ptr() );
			pWnd = p_wnd.ptr();

			p_wnd.Reset();
			return true;
		}

		RETURN_ERROR( "unsupported window type" );
	}
	
/*
=================================================
	
=================================================
*/
	void CMainWindow::_FreeShared(IWindow *pWnd)
	{
		FOR( i, _aShared ) {
			if ( pWnd == _aShared[i] ) {
				_aShared.FastErase( i );
				return;
			}
		}
	}
	
/*
=================================================
	
=================================================
*/
	IWindow * CMainWindow::ParentWindow()
	{
		return nullptr;
	}
	


//------------------------ CRenderWindow --------------------------//
/*
=================================================
	
=================================================
*/
	CRenderWindow::CRenderWindow(IWindow *pParent):
		IWindow( &_cThread, &_cWindow, &_cRender ), _pParent(pParent)
	{}

/*
=================================================
	
=================================================
*/
	CRenderWindow::~CRenderWindow()
	{
		if ( _pParent != nullptr )
			_pParent->_FreeShared( this );
	}

/*
=================================================
	
=================================================
*/
	bool CRenderWindow::Create(const TGLWindow::TDescriptorExt &sDesc, const char *pCaption, TWindowClass *pClass)
	{
		CHECK_RETURN( _cWindow.CreateGLInThread( _cThread.GetThread(), sDesc, pCaption, pClass ) );
		_cWindow.AddUpdater( &_cThread );

		CHECK_RETURN( _cInput.Init( &_cWindow ) );
		_cWindow.Show();

		THREADMAN()->AddThread( _pThread );
		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool CRenderWindow::CreateShared(e_thread::type eType, IWindow *&pWnd)
	{
		CHECK_VALUE( _pParent != nullptr, );
		CHECK_RETURN( _pParent->CreateShared( eType, pWnd ) );
		return true;
	}
	
/*
=================================================
	
=================================================
*/
	void CRenderWindow::_FreeShared(IWindow *pWnd)
	{
		CHECK_VALUE_R( _pParent != nullptr, );
		_pParent->_FreeShared( pWnd );
	}
	
/*
=================================================
	
=================================================
*/
	IWindow * CRenderWindow::ParentWindow()
	{
		return _pParent;
	}
	


//------------------------- CLoadWindow ---------------------------//
/*
=================================================
	
=================================================
*/
	CLoadWindow::CLoadWindow(IWindow *pParent):
		IWindow( &_cThread, &_cWindow, &_cRender ), _pParent(pParent)
	{
	}

/*
=================================================
	
=================================================
*/
	CLoadWindow::~CLoadWindow()
	{
		if ( _pParent != nullptr )
			_pParent->_FreeShared( this );
	}

/*
=================================================
	
=================================================
*/
	bool CLoadWindow::Create(const TGLWindow::TDescriptorExt &sDesc, const char *pCaption, TWindowClass *pClass)
	{
		CHECK_RETURN( _cWindow.CreateGLInThread( _cThread.GetThread(), sDesc, pCaption, pClass ) );
		_cWindow.AddUpdater( &_cThread );

		CHECK_RETURN( _cInput.Init( &_cWindow ) );
		_cWindow.Show();

		THREADMAN()->AddThread( _pThread );
		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool CLoadWindow::CreateShared(e_thread::type eType, IWindow *&pWnd)
	{
		CHECK_VALUE( _pParent != nullptr, );
		CHECK_RETURN( _pParent->CreateShared( eType, pWnd ) );
		return true;
	}
	
/*
=================================================
	
=================================================
*/
	void CLoadWindow::_FreeShared(IWindow *pWnd)
	{
		CHECK_VALUE_R( _pParent != nullptr, );
		_pParent->_FreeShared( pWnd );
	}
	
/*
=================================================
	
=================================================
*/
	IWindow * CLoadWindow::ParentWindow()
	{
		return _pParent;
	}

//-------------------------------------------------------------------

}	// CoreSystems
}	// Engine